#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <ffmpeg/avformat.h>
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avio.h>

#include <math.h>

#include "decode.h"
#include "global.h"


#define FILE_NAME_SIZE 1024

#define VIDEO_SIZEOUT width*height*3/2



unsigned char* picture2yuv(AVFrame *picture)
{

	int h;
	int size, linesize;
	unsigned char *p_preimagebuffer;
	unsigned char *p_imagebuffer;

	p_imagebuffer = malloc(VIDEO_SIZEOUT);
	if (p_imagebuffer == NULL)
		return NULL;

	size = height*width;
	p_preimagebuffer = p_imagebuffer;

	linesize = picture->linesize[0];
	for ( h = 0; h < height; h++ ){
		memcpy( p_imagebuffer + h*width, picture->data[0] + h*linesize, width );
	}

	p_imagebuffer += size;
	linesize = picture->linesize[1];
	for ( h = 0; h < height/2; h++ ){
		memcpy( p_imagebuffer + h*width/2, picture->data[1] + h*linesize, width/2 );
	}

	p_imagebuffer += size/4;
	linesize = picture->linesize[2];
	for ( h = 0; h < height/2; h++ ){
		memcpy( p_imagebuffer + h*width/2, picture->data[2] + h*linesize, width/2 );
	}

	p_imagebuffer = p_preimagebuffer;

	return p_imagebuffer;
}

static void flush_packet_queue(AVFormatContext *s)
{
	AVPacketList *pktl;

	for(;;) {
		pktl = s->packet_buffer;
		if (!pktl)
			break;
		s->packet_buffer = pktl->next;
		av_free_packet(&pktl->pkt);
		av_free(pktl);
	}
}

static void av_read_frame_flush(AVFormatContext *s)
{
	AVStream *st;
	int i;

	flush_packet_queue(s);

	/* free previous packet */
	if (s->cur_st) {
		if (s->cur_st->parser)
			av_free_packet(&s->cur_pkt);
		s->cur_st = NULL;
	}
	/* fail safe */
	s->cur_ptr = NULL;
	s->cur_len = 0;

	/* for each stream, reset read state */
	for(i = 0; i < s->nb_streams; i++) {
		st = s->streams[i];

		if (st->parser) {
			av_parser_close(st->parser);
			st->parser = NULL;
		}
		st->last_IP_pts = AV_NOPTS_VALUE;
		st->cur_dts = 0; /* we set the current DTS to an unspecified origin */
	}
}





struct mpeg_decode* hunter_decode_alloc(char* file_name) 
{
	struct mpeg_decode* md;


	md = (struct mpeg_decode*) malloc(sizeof(struct mpeg_decode));
	if (!md) {
		fprintf( stderr, "Failed to hutern decode alloc\n" );
		return NULL;
	}

	md->ic = av_alloc_format_context();
	md->picture = (AVFrame *)av_mallocz(sizeof(AVFrame));
	strcpy(md->file_name, file_name);

	md->rgb_data = (unsigned char*)malloc(sizeof(unsigned char)*width*height*3);
	if (md->rgb_data == NULL) 
		return NULL;

	md->is_update = 0;

	return md;
}
int hunter_decode_init(struct mpeg_decode* p_mpeg) 
{
	AVFormatContext* ic;
	AVCodecContext *enc;
	AVCodec *codec;
	int i, ret;

	AVIndexEntry *ie;
	AVStream *st;
	int index;


	pthread_mutex_init(&p_mpeg->pos_mutex, NULL);

	ret = av_open_input_file(&(p_mpeg->ic), p_mpeg->file_name, NULL, 0, NULL);
	if (ret < 0) {
		fprintf(stderr, "Error : av_open_input_file\n");
		return -1;
	}

	ret = av_find_stream_info(p_mpeg->ic);
	if (ret < 0) {
		fprintf(stderr, "Error : av_find_stream_info\n");
		return -1;
	}


	dump_format(p_mpeg->ic, 0, p_mpeg->file_name, 0);
	ic = p_mpeg->ic;
	for (i = 0; i < ic->nb_streams; i++) {
		enc = ic->streams[i]->codec;
		codec = avcodec_find_decoder(enc->codec_id);
		if (codec) {
			avcodec_open(enc, codec);
		}
		switch(enc->codec_type) {
			case CODEC_TYPE_AUDIO:
				p_mpeg->audio_index = i;
				break;
			case CODEC_TYPE_VIDEO:
				p_mpeg->video_index = i;
				break;
			default:
				break;
		}
	}
	return 1;
}
void hunter_decode_pos_set(struct mpeg_decode* p_mpeg, int pos)
{
	av_read_frame_flush(p_mpeg->ic);
	url_fseek(&p_mpeg->ic->pb, pos, SEEK_SET);

}
int hunter_decode_get(struct mpeg_decode* p_mpeg, unsigned char** data)
{
	AVFormatContext *ic = p_mpeg->ic;
	AVPacket pkt1, *pkt = &pkt1;
	AVCodecContext *enc;
	unsigned char *ptr;
	int len, len1, got_picture;
	int ret;

	do {
		ret = av_read_frame(p_mpeg->ic, pkt);
		if (ret < 0) {
			fprintf(stderr, "End\n");
			return -1;
		}
		if (pkt->stream_index != p_mpeg->video_index)
			av_free_packet(pkt);
	} while(pkt->stream_index != p_mpeg->video_index);	 
	ptr = pkt->data;
	len = pkt->size;
	enc = p_mpeg->ic->streams[p_mpeg->video_index]->codec;

	while(len > 0) {
		len1 = avcodec_decode_video(enc, p_mpeg->picture, &got_picture, ptr, len);
		if (got_picture) {
			(*data) = picture2yuv(p_mpeg->picture);
			if (!*data) return -1;
			av_free_packet(pkt);
			//return 1;

		}
		ptr += len1;
		len -= len1;
	}

	av_free_packet(pkt);
	return 1;

}
void hunter_decode_close(struct mpeg_decode* p_mpeg)
{
	if (p_mpeg) {
		if (p_mpeg->rgb_data)
			free (p_mpeg->rgb_data);
		if (p_mpeg->ic)
			free (p_mpeg->ic);
		if (p_mpeg->picture)
			free (p_mpeg->picture);
		free (p_mpeg);
	}
}


